.. _Tutorial converting a NeurEco Regression model to a Keras model: Tutorial: converting a NeurEco Regression model to a Keras model ================================================================== NeurEco Tabular offers the user the possibility to convert a model to a keras model to be used with TensorFlow. .. note:: * This feature is only available for the python API. * This feature requires an existing installation of TensorFlow 2.x and keras. he following section will use the test case :std:ref:`Energy consumption test case`. This test case is delivered with the NeurEco installation package. The first step will be to load the data and build a model: .. code-block:: python import numpy as np from NeurEco import NeurEcoTabular as Tabular ''' Load the training data ''' print("Loading the training data".center(60, "*")) x_train = np.genfromtxt("x_train.csv", delimiter=";", skip_header=True) y_train = np.genfromtxt("y_train.csv", delimiter=";", skip_header=True) y_train = np.reshape(y_train, (-1, 1)) ''' create a NeurEco Object to build the model''' print("Creating the NeurEco builder".center(60, "*")) builder = Tabular.Regressor() ''' Building the NeurEco Model ''' builder.build(input_data=x_train, output_data=y_train, # the rest of these parameters are optional write_model_to="./EnergyConsumptionModel/EnergyConsumption.ednn", checkpoint_address="./EnergyConsumptionModel/EnergyConsumption.checkpoint", valid_percentage=33.33, inputs_shifting="min_centered", inputs_scaling="max_centered") ''' Delete the builder from memory''' print("Deleting the NeurEco builder".center(60, "*")) builder.delete() Once the build is done, and the model is saved, let's convert it to a keras model. To do so, we first need to import the proper library: .. code-block:: python from NeurEco import NeurEco2Keras Once that's done, we will convert the ednn model to a keras model, and we will print out its summary: .. code-block:: python neureco_model_path = "./EnergyConsumptionModel/EnergyConsumption.ednn" keras_model = NeurEco2Keras.neureco2keras(neureco_model_path) keras_model.summary() .. code-block:: text Model: "EnergyConsumption_NeurEco_Keras_Model" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= input (InputLayer) [(None, 5)] 0 _________________________________________________________________ tf_op_layer_centeredInputs ( [(None, 5)] 0 _________________________________________________________________ tf_op_layer_normalizedInputs [(None, 5)] 0 _________________________________________________________________ adagos_gemm (AdagosGemm) (None, 8) 48 _________________________________________________________________ tf_op_layer_x1TensorActivati [(None, 8)] 0 _________________________________________________________________ adagos_gemm_1 (AdagosGemm) (None, 1) 9 _________________________________________________________________ tf_op_layer_outputDescaled ( [(None, 1)] 0 _________________________________________________________________ tf_op_layer_output (TensorFl [(None, 1)] 0 ================================================================= Total params: 57 Trainable params: 57 Non-trainable params: 0 _________________________________________________________________ .. note:: The number of links (NeurEco model) is slightly different than the number of trainable parameters (keras model). This is because the keras models are naturally fully connected, and some of the weights are present in the keras model although they are not needed (they have a value of 0). At this stage, we can evaluate the two models (NeurEco and Keras), and see the difference between them: .. code-block:: python x_test = np.genfromtxt("x_test.csv", delimiter=";")[1:, :] ''' evaluate the model using neureco ''' neureco_model = Tabular.Regressor() neureco_model.load(neureco_model_path) neureco_output = neureco_model.evaluate(x_test) ''' evaluate the model using keras ''' keras_output = keras_model.predict(x_test.astype("float32")) ''' compare the models results ''' error = np.linalg.norm(keras_output - neureco_output) / np.linalg.norm(neureco_output) print("Error between the models:", error) .. code-block:: text Error between the models: 1.6618171240269623e-07 The keras model can be saved and restored for later use. For example, we can save it as a h5 model to the disk: .. code-block:: python import tensorflow as tf keras_model.save("./EnergyConsumptionModel/EnergyConsumption.h5") We can now reload it from the disk. However, a custom class is needed to perform the load. This class is called *AdagosGemm* and is in the library *NeurEco2Keras*. To load the model simply run: .. code-block:: python import tensorflow as tf reloaded_keras_model = tf.keras.models.load_model("./EnergyConsumptionModel/EnergyConsumption.h5", custom_objects={'AdagosGemm': NeurEco2Keras.AdagosGemm}) If the user doesn't have the possibility to import *NeurEco2keras* in its production environment, simply copy and paste the following class: .. code-block:: python class AdagosGemm(tf.keras.layers.Layer): def __init__(self, w_init, b_init, alpha, beta, w_name, b_name, comp=False, name=None, **kwargs): super(AdagosGemm, self).__init__(name=name) self.trainable = not comp self.w_init = w_init self.b_init = b_init self.alpha = alpha self.beta = beta self.w_name = w_name self.b_name = b_name self.w = None self.b = None def get_config(self): config = super().get_config() config.update({"trainable": self.trainable, "w_init": self.w_init, "b_init": self.b_init, "alpha": self.alpha, "beta": self.beta, "w_name": self.w_name, "b_name": self.b_name, "w": self.w.numpy(), "b": self.b.numpy()}) return config def build(self, input_shape): self.w = self.add_weight(shape=self.w_init, name=self.w_name, trainable=self.trainable) self.b = self.add_weight(shape=self.b_init, name=self.b_name, trainable=self.trainable) self.built = True def call(self, a): return self.alpha * tf.matmul(a, self.w) + self.beta * self.b To load the model in this case, we will change the custom object to this class: .. code-block:: python import tensorflow as tf reloaded_keras_model = tf.keras.models.load_model("./EnergyConsumptionModel/EnergyConsumption.h5", custom_objects={'AdagosGemm': AdagosGemm}) We can evaluate the reloaded model on the testing data, and compare it to the neureco_outputs obtained previously: .. code-block:: python ''' evaluate the model using keras ''' reloaded_keras_output = reloaded_keras_model.predict(x_test.astype("float32")) ''' compare the models results ''' error = np.linalg.norm(reloaded_keras_output - neureco_output) / np.linalg.norm(neureco_output) print("Error between the models (NeurEco and reloaded):", error) .. code-block:: text Error between the models (NeurEco and reloaded): 1.6618171240269623e-07